<?php

namespace app\scaffold;

use app\exception\TableExistException;
use think\facade\Db;

class ModelCreator
{
    /**
     * Error message
     *
     * @var string
     */
    protected $errMsg;
    /**
     * Table nme
     *
     * @var string
     */
    protected $tableName;

    /**
     * Model name
     */
    protected $name;

    /**
     * Model Class name
     *
     * @var string
     */
    protected $className;

    /**
     * Model type
     */
    protected $type;

    protected $comment;

    /**
     * The filesystem instance
     * 
     * @var \think\Filesystem
     */
    protected $files;

    /**
     * ModelCreator construct
     *
     * @param $tableName
     */
    public function __construct($tableName,$tableComment)
    {   
        $this->errMsg = $tableName;

        $this->tableName = config('database')['connections'][config('database')['default']]['prefix'].App('http')->getName().$tableName;

        $this->className= ucfirst(camelize(mb_strtolower(App('http')->getName().$tableName)));

        $this->name = App('http')->getName().$tableName;

        $this->comment = $tableComment;
    }

    /**
     * @throws \Exception
     */
    public function destroy()
    {
        $this->dropTable($this->tableName);
        $this->deleteFile($this->getPath($this->className,'model'));
    }

    /**
     * Delete the file at a given path.
     *
     * @param  string|array  $paths
     * @return bool
     */
    public function deleteFile($paths): bool
    {
        $paths = is_array($paths) ? $paths : func_get_args();

        $success = true;

        foreach ($paths as $path) {
            try {
                if (! @unlink($path)) {
                    $success = false;
                }
            } catch (\Exception $e) {
                $success = false;
            }
        }

        return $success;
    }

    /**
     * @throws \Exception
     */
    public function create($timestamps=true): array
    {

        $flag = $this->createTable($this->tableName);

        if(!$flag){
            throw new \Exception('table create failed');
        }
        $path = $this->getPath($this->className,'model');
        $dir = dirname($path);
        if (!is_dir($dir)) {
            mkdir($dir, 0755, true);
        }
        if (file_exists($path)) {
            throw new \Exception("Model [$this->errMsg] already exists!");
        }
        $stub = file_get_contents($this->getStub());
        $stub = $this->replaceClass($stub,$this->className)
            ->replaceNamespace($stub,$dir)
            ->replaceSpace($stub);
        file_put_contents($path,$stub);
        chmod($path,0777);
        return dataReturn(0,'模型创建成功',$path);
    }

    /**
     * @param $name
     * @return bool
     * @throws \Exception
     */
    public function dropTable($name): bool
    {
        $has_table = $this->hasTable($name);
        if(!$has_table){
            return true;
        }
        $drop_sql = "DROP TABLE $name";
        $res = Db::execute($drop_sql);
        return empty($res);
    }

    /**
     * Create model table
     *
     * @param string $name
     * @return boolean
     * @throws \Exception
     */
    public function createTable(string $name): bool
    {
        $has_table = $this->hasTable($name);
        if($has_table){
            throw new TableExistException();
        }
        $tableComment = '\''.$this->comment . '表'.'\'';
        $create_sql = "CREATE TABLE `$name` (
            `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
            `seller_id` bigint unsigned NULL COMMENT '商户ID',
            `lang` varchar(255) null default 'zh' comment '语言标识',
            `lang_pid` int null default '0' comment '语言锚点',
            `sub_id` bigint unsigned NULL  COMMENT '副表ID',
            `create_time` int COMMENT '创建时间',
            `update_time` int COMMENT '更新时间',
            PRIMARY KEY(`id`) 
        )ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT=$tableComment;";
        $res = Db::execute($create_sql);
        return empty($res);
    }

    /** 
     * Has Table
     *
     * @param string $name
     * @return boolean
     */
    public function hasTable(string $name): bool
    {
        $database = env('database.database');
        $exists = Db::query("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES 
        WHERE TABLE_SCHEMA = :database AND TABLE_NAME = :name ", 
        ['database' => $database,'name' => $name]);
        return !empty($exists);
    }

    /**
     * Get file path
     *
     * @param string $name
     * @return string
     */
    public function getPath(string $name, $type): string
    {
        return (new Helper())->getPath($name,$type);
    }

    public function getAppName()
    {
        return (new Helper())->getAppName();
    }

    public function destory()
    {
    }

    /**
     * Get namespace of giving class full name
     *
     * @param string $name
     * @return string
     */
    public function getNamespace(string $name): string
    {

        $spaceStr = trim(implode('\\',(explode(DIRECTORY_SEPARATOR,$name))),'\\');
        return trim(strstr($spaceStr,'\\app'),'\\');
    }

    public function replaceModelName(&$stub,$tableName): ModelCreator
    {
        $stub = str_replace('DummyModelName',"protected \$name = '$tableName';",$stub);
        return $this;
    }

    /**
     * Replace class dummy
     *
     * @param string $stub
     * @param string $name
     * @return $this
     */
    public function replaceClass(string &$stub, string $name): ModelCreator
    {
        $stub = str_replace('DummyClass',$name,$stub);
        return $this;
    }

        /**
     * Replace namespace dummy.
     *
     * @param string $stub
     * @param string $name
     *
     * @return $this
     */
    protected function replaceNamespace(string &$stub, string $name): ModelCreator
    {
        $stub = str_replace(
            'DummyNamespace',
            $this->getNamespace($name),
            $stub
        );

        return $this;
    }

    /**
     * Replace timestamps dummy.
     *
     * @param string $stub
     * @param bool $timestamps
     *
     * @return $this
     */
    protected function replaceTimestamp(string &$stub, bool $timestamps): ModelCreator
    {
        $useTimestamps = $timestamps ? "protected \$autoWriteTimestamp = true;\n" : '';

        $stub = str_replace('DummyTimestamp', $useTimestamps, $stub);

        return $this;
    }

        /**
     * Replace spaces.
     *
     * @param string $stub
     *
     * @return mixed
     */
    public function replaceSpace(string $stub)
    {
        return str_replace(["\n\n\n", "\n    \n"], ["\n\n", ''], $stub);
    }

    /**
     * Get stub path of model.
     *
     * @return string
     */
    public function getStub(): string
    {
        return __DIR__.'/stubs/model.stub';
    }

}
